package m.jclecai.com.view.klpk;

import android.content.Context;
import android.support.v4.view.ViewCompat;
import android.support.v4.widget.ViewDragHelper;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.widget.FrameLayout;


import m.jclecai.com.utils.BaseUtils;

/**
 * Created by andy on 2017/6/6.
 * 这里的话，我们是不支持无平滑过渡，无平滑过渡就会产生一个bug，导致出现问题；
 */

public class PullLayout extends FrameLayout {

    ViewDragHelper mDragHelper;
    private ViewGroup mInnerLayout;
    private ViewGroup mOutterLayout;
    private int mInnerLayoutHeight;
    private int mOutterHeight;
    private int mOutterWidth;

    public int toMoveTop = 100;
    private int mOutterLayoutTop;
    private int mMeasuredHeight;

    public PullLayout(Context context) {
        this(context, null);
    }

    public PullLayout(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public PullLayout(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        //这里的话， 我们将初始化ViewDragHelper对象；
        mDragHelper = ViewDragHelper.create(this, callBack);
    }

    //这里话，我们要做的一个操作就复杂了，由之前的水平，我们将换成垂直方向上的；
    ViewDragHelper.Callback callBack = new ViewDragHelper.Callback() {

        @Override
        public boolean tryCaptureView(View child, int pointerId) {
            //如果是外边的布局我们就尝试捕获；
            return child == mOutterLayout;
        }

        @Override
        public int getViewVerticalDragRange(View child) {
            return mInnerLayoutHeight;
        }

        //这里表示将要移动但是还没有移动的情况；
        @Override
        public int clampViewPositionVertical(View child, int top, int dy) {
            //这里的话， 我们要做的一个操作就是对移动的位置进行一个修正；
            if (child == mOutterLayout) {
                top = fixTop(top);
            }
            return top;
        }

        //这个方法里面我们要做的一个操作就是联动的实现；
        @Override
        public void onViewPositionChanged(View changedView, int left, int top, int dx, int dy) {
            int fixTop = 0;
            if (changedView == mOutterLayout) {
                //这里的top最大值不会超过mInnerLayout的高度；
                fixTop = top;
                //这里我们对pullLayout进行一个优化，防止过度绘制；
                if(top<=0){
                    mInnerLayout.setVisibility(View.INVISIBLE);
                }else{
                    mInnerLayout.setVisibility(View.VISIBLE);
                }
            }
            startAnim(fixTop);
            dispachDragEvent(fixTop);
        }

        //这里的话，我们是需要处理手指松动的动画的逻辑；
        @Override
        public void onViewReleased(View releasedChild, float xvel, float yvel) {
            System.out.println("yvel: " + yvel + "mInnerLayoutHeight:" + mInnerLayoutHeight + "==top:" + mOutterLayout.getTop());
            if (mOutterLayout.getTop() < 0) {
                //我们是不做任何操作的
            } else if (yvel == 0 && mOutterLayout.getTop() > mInnerLayoutHeight / 2) {
                //这样的话，我们也是认为其是打开的；
                open();
            } else if (yvel > 2000) {
                //速度大于2000才让其打开，因为防止误操作,这里的话表示的是打开的；
                open();
            } else {
                //这里的话表示是关闭；
                close();
            }
        }
    };

    //这里的话，我们是需要关闭的；
    public void close() {

        smoothClose(true);
    }


    //打开的；
    public void open() {
        smoothOpen(true);
    }

    private void smoothOpen(boolean isSmooth) {

        if (isSmooth) {
            if (mDragHelper.smoothSlideViewTo(mOutterLayout, 0, mInnerLayoutHeight)) {
                ViewCompat.postInvalidateOnAnimation(this);
            }
        } else {
            //暂时不做；
        }
    }

    @Override
    public void computeScroll() {
        if (mDragHelper.continueSettling(true)) {
            ViewCompat.postInvalidateOnAnimation(this);
        }
    }

    private void smoothClose(boolean isSmooth) {

        if (isSmooth) {

            if (mDragHelper.smoothSlideViewTo(mOutterLayout, 0, 0)) {
                ViewCompat.postInvalidateOnAnimation(this);
            }

        } else {
            //暂时不做
        }

    }

    public OnDragStatusChange mOnDragStatusChange;

    public void setOnDragStatusChange(OnDragStatusChange onDragStatusChange) {
        mOnDragStatusChange = onDragStatusChange;
    }

    //暴露接口；
    public interface OnDragStatusChange {
        void onOpen();

        void onClose();

        void OnDrag(float percent);
    }

    public void toggle() {
        if (mCurStaus == Status.close) {
            open();
        } else {
            close();
        }
    }


    public enum Status {
        open, close, dragging
    }

    public Status mCurStaus = Status.close;

    //这里我将事件暴露出去，供别人使用；这里的话，我们应该将进度的百分比给弄出去，
    // 这样的话，如果有其他的动画需要联动的话，我们我们也是可以实现联动的效果；
    private void dispachDragEvent(int fixTop) {
        //这里的话，我们获取得到百分比；
        float percent = fixTop * 1.0f / mInnerLayoutHeight;
        if (mOnDragStatusChange == null) {
            return;
        }
        //这里如果不设置状态的话，我们在外边是没有办法点击打开的；

        mCurStaus = updateDragStatus(percent);
        if (mCurStaus.equals(Status.open)) {
            mOnDragStatusChange.onOpen();
        } else if (mCurStaus.equals(Status.close)) {
            mOnDragStatusChange.onClose();
        } else {
            mOnDragStatusChange.OnDrag(percent);
        }
    }

    private Status updateDragStatus(float percent) {
        //这里我们要实现相应的功能；
        if (percent == 0) {
            return Status.close;
        } else if (percent == 1) {
            return Status.open;
        }
        return Status.dragging;
    }

    //这里的话，我们将进行一个动画，；
    private void startAnim(int fixTop) {
        //这里的话，我们在拖动OutLayout的时候，我们是需要InnerLayout有一个慢慢的向下的滚动的动画；
        float percent = fixTop * 1.0f / mInnerLayoutHeight;
        //根据这个百分比我们将实现相应的动画；
        Float evaluate = evaluate(percent, 0, BaseUtils.dip2px(getContext(), 50));
        mInnerLayout.setTranslationY(evaluate);
    }

    public static Float evaluate(float fraction, Number startValue, Number endValue) {
        float startFloat = startValue.floatValue();
        return startFloat + fraction * (endValue.floatValue() - startFloat);
    }

    /**
     * 这里我们对高度进行一个修正，
     *
     * @param top
     * @return
     */
    private int fixTop(int top) {


        //这里的话，我们要对其进行一个修正；
        if (top < -toMoveTop) {
            top = -toMoveTop;
        } else if (top > mInnerLayoutHeight) {
            top = mInnerLayoutHeight;
        }
        return top;
    }

    /**
     * 这里的话，我们将进行的一个操作就是获取子布局；
     * 当我们拖动外边的布局的时候，里面的布局其实是会发生变化的；
     */
    @Override
    protected void onFinishInflate() {
        mInnerLayout = ((ViewGroup) getChildAt(0));
        mOutterLayout = ((ViewGroup) getChildAt(1));
    }


    /**
     * 这里我们是可以获取布局的相应的高度的；我们通过滑动布局的相应的高度；
     *
     * @param w
     * @param h
     * @param oldw
     * @param oldh
     */
    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        super.onSizeChanged(w, h, oldw, oldh);
        //这个是里面的布局的一个高度；这里-2的原因，在我的手机上，有时候会出现空隙的现象，
        childSizeChange();

    }

    public void measure(){
        int measureSpec = MeasureSpec.makeMeasureSpec(1 << 30 - 1, MeasureSpec.AT_MOST);
        mInnerLayout.measure(measureSpec,measureSpec);
        mOutterLayout.measure(measureSpec,measureSpec);
        childSizeChange();
    }

    //这里的话，我们重新计算高度
    public void childSizeChange(){
        mInnerLayoutHeight = mInnerLayout.getMeasuredHeight() - 2;
        mOutterHeight = mOutterLayout.getMeasuredHeight();
        mOutterWidth = mOutterLayout.getMeasuredWidth();
        System.out.println("pullLayout: "+"mInnerLayoutHeight: "+mInnerLayoutHeight+"mOutterHeight"+mOutterHeight);
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {

        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        mMeasuredHeight = mOutterLayout.getMeasuredHeight();

    }

    @Override
    protected void onLayout(boolean changed, int left, int top, int right, int bottom) {

        //防止多次调用；
        super.onLayout(changed, left, top, right, bottom);
        mOutterLayoutTop = mOutterLayout.getTop();

    }


    @Override
    public boolean onInterceptTouchEvent(MotionEvent ev) {
        return mDragHelper.shouldInterceptTouchEvent(ev);
    }


    @Override
    public boolean onTouchEvent(MotionEvent event) {
        //将事件交给ViewDragHelper来处理；
        mDragHelper.processTouchEvent(event);
        return true;
    }


    ///==设置向上滚动的距离==
    public int getToMoveTop() {
        return toMoveTop;
    }

    public void setToMoveTop(int toMoveTop) {
        this.toMoveTop = toMoveTop;
    }
}
